﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class SkinnedMeshRendererBatch
{
    [SerializeField]
    public GameObject Target;
    [Tooltip("是否合并网格贴图")]
    public bool is_CombineMeshes = false;

    bool yetCombine = false;

    public void Start()
    {
        if (yetCombine)
            return;

        GameObject playerClone = Target;

        List<CombineInstance> combineInstances = new List<CombineInstance>();
        Material material = null;
        List<Transform> bones = new List<Transform>();
        List<Texture2D> textures = new List<Texture2D>();
        List<Vector2[]> uvList = new List<Vector2[]>();
        int uvCount = 0;

        Renderer[] skinnedMeshs = playerClone.GetComponentsInChildren<Renderer>();
        Transform[] transforms = playerClone.GetComponentsInChildren<Transform>();

        for (int num = 0; num < skinnedMeshs.Length; num++)
        {
            Renderer temp = skinnedMeshs[num];
            SkinnedMeshRenderer skintemp = skinnedMeshs[num] as SkinnedMeshRenderer;
            MeshFilter mfilter = temp.gameObject.GetComponent<MeshFilter>();
            if (material == null)
            {//返回分配给渲染器的第一个材质
                material = temp.sharedMaterial;
            }

            //合并网格
            CombineInstance ci = new CombineInstance();
            ci.mesh = skintemp !=null ? skintemp.sharedMesh : temp.gameObject.GetComponent<MeshFilter>().sharedMesh;
            //子网格索引
            //ci.subMeshIndex = num;
            //合并之前网格变换的矩阵
            ci.transform = temp.transform.localToWorldMatrix;
            //变换矩阵有问题（就用这句），要保持相对位置不变，要转换为父节点的本地坐标，
            //ci.transform = transform.worldToLocalMatrix * temp.transform.localToWorldMatrix;
            combineInstances.Add(ci);

            //取得temp相对应名称的骨骼列表 
            int startBoneIndex = bones.Count;
            //if(num == 0)
            //skintemp.bones = new List<Transform>(){ Target.transform.Find("Bip001") }.ToArray();
            if (skintemp != null)
                foreach (Transform t in skintemp.bones)
                {
                    foreach (Transform transform in transforms)
                    {
                        if (transform.name != t.name)
                            continue;
                        bones.Add(transform);
                        break;
                    }
                }

            //储存网格纹理坐标
            uvList.Add(skintemp != null ? skintemp.sharedMesh.uv : mfilter.sharedMesh.uv);
            uvCount += skintemp != null ? skintemp.sharedMesh.uv.Length : mfilter.sharedMesh.uv.Length;

            //子网格
            int subMeshCnt = skintemp != null ? skintemp.sharedMesh.subMeshCount : mfilter.sharedMesh.subMeshCount;
            int endBoneIndex = bones.Count;
            for (int i = 1; i < subMeshCnt; ++i)
            {
                for (int jj = startBoneIndex; jj < endBoneIndex; ++jj)
                {
                    bones.Add(bones[jj]);
                }
            }

            //贴图记录
            if (temp.material.mainTexture != null)
            {
                Texture2D t2 = temp.GetComponent<Renderer>().material.mainTexture as Texture2D;

                textures.Add(t2);
            }
            temp.gameObject.SetActive(false);
        }

        int altalsSize = textures.Count > 12 ? 2048 : 2048;
        //贴图合并（注意合并最大尺寸）
        Texture2D skinnedMeshAtlas = new Texture2D(altalsSize, altalsSize);
        Texture2D[] texArr = textures.ToArray();

        //Rect[] packingResult = skinnedMeshAtlas.PackTextures(texArr, 0);

        int cnt = texArr.Length;
        List<Rect> rectList = new List<Rect>();
        for (int i = 0; i < cnt;i++)
        {
            Rect rec = new Rect();

            int ix = i % 4;
            int iy = i / 4;
            rec.x = ix * 512;
            rec.y = iy * 512;
            rec.width = 512;
            rec.height = 512;
            rectList.Add(rec);

            SetTexture(texArr[i],rec);
        }


        //网格纹理坐标合并
        Vector2[] atlasUVs = new Vector2[uvCount];
        int j = 0;
        //for (int i = 0; i < uvList.Count; i++)
        //{
        //    foreach (Vector2 uv in uvList[i])
        //    {
        //        atlasUVs[j].x = Mathf.Lerp(rectList[i].xMin, packingResult[i].xMax, uv.x);
        //        atlasUVs[j].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y);
        //        j++;
        //    }
        //}

        for (int i = 0; i < uvList.Count; i++)
        {
            foreach (Vector2 uv in uvList[i])
            {
                atlasUVs[j].x = Mathf.Lerp(rectList[i].xMin, rectList[i].xMax, uv.x);
                atlasUVs[j].y = Mathf.Lerp(rectList[i].yMin, rectList[i].yMax, uv.y);
                j++;
            }
        }


        //蒙皮网格渲染器
        SkinnedMeshRenderer r = playerClone.GetComponent<SkinnedMeshRenderer>();
        if(r == null)
            r = playerClone.AddComponent<SkinnedMeshRenderer>();

        r.sharedMesh = new Mesh();
        //第二个参数是否合并成同一个材质 参数三为false，在CombineInstance结构变换矩阵将被忽略。 
        r.sharedMesh.CombineMeshes(combineInstances.ToArray(), true, false);
        r.bones = bones.ToArray();
        r.material = material;
        //r.material.mainTexture = skinnedMeshAtlas;
        r.material.mainTexture = mainTexture;
        r.sharedMesh.uv = atlasUVs;

        //MeshFilter newMesh = playerClone.AddMissingComponent<MeshFilter>();
        //newMesh.sharedMesh = r.sharedMesh;

        yetCombine = true;
    }

    //=========================================
    Material material;
    RenderTexture mainTexture;
    int MainTex_ID;
    public void SetTexture(Texture2D texture, Rect rect)
    {
        if (material == null)
        {
            Shader sd = Shader.Find("CharactorPBR");
            material = new Material(sd);

            MainTex_ID = Shader.PropertyToID("_MainTex");

            mainTexture = RenderTexture.GetTemporary(2048, 2048, 0, RenderTextureFormat.ARGB32);
        }

        material.SetTexture(MainTex_ID, texture);

        if (material.SetPass(0))
        {
            Graphics.SetRenderTarget(mainTexture);

            GL.PushMatrix();
            GL.LoadOrtho();
            GL.Begin(GL.QUADS);
            {
                Vector3 vertex1 = new Vector3(rect.x, rect.y, 0);
                Vector3 vertex2 = new Vector3(rect.x, rect.y + rect.height, 0);
                Vector3 vertex3 = new Vector3(rect.x + rect.width, rect.y + rect.height, 0);
                Vector3 vertex4 = new Vector3(rect.x + rect.width, rect.y, 0);

                GL.TexCoord2(0, 0);
                GL.Vertex(vertex1);

                GL.TexCoord2(0, 1);
                GL.Vertex(vertex2);

                GL.TexCoord2(1, 1);
                GL.Vertex(vertex3);

                GL.TexCoord2(1, 0);
                GL.Vertex(vertex4);
            }
            GL.End();
            GL.PopMatrix();
        }
            

        material.SetTexture(MainTex_ID, mainTexture);
    }
}
